package frame.options.simulation;

import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;

import model.algorithms.embedding.EmbeddingAlgorithm;
import model.algorithms.linksMapping.LinksMappingAlgorithm;
import model.algorithms.nodesMapping.NodesMappingAlgorithm;
import model.algorithms.rounding.RoundingAlgorithm;
import model.algorithms.splitting.SplittingAlgorithm;
import model.components.networks.Network;
import model.components.networks.sdn.SdnNetwork;
import model.components.networks.virtual.VirtualNetwork;
import frame.SimulatorFrame;
import frame.networks.tables.NetworksTableTabbedPane;
import frame.networks.tables.sdn.SdnTableModel;
import frame.networks.tables.virtual.VirtualTableModel;
import frame.options.simulation.create.CreateSimulationWizard;
import frame.options.simulation.create.backup.BackupDescriptor;
import frame.options.simulation.create.coordinated.CoordinatedDescriptor;
import frame.options.simulation.create.cost.CostDescriptor;
import frame.options.simulation.create.embedding.EmbeddingDescriptor;
import frame.options.simulation.create.links.LinksDescriptor;
import frame.options.simulation.create.nodes.NodesDescriptor;
import frame.options.simulation.create.rounding.RoundingDescriptor;
import frame.options.simulation.create.sdn.SdnDescriptor;
import frame.options.simulation.create.splitting.SplittingDescriptor;
import frame.options.simulation.create.virtual.VirtualDescriptor;
import frame.options.simulation.running.RunningFrame;

@SuppressWarnings("serial")
public class CreateSimulationMenuItem extends JMenuItem implements ActionListener
{
	private SimulatorFrame simulatorFrame;
	public SimulatorFrame getFrame(){ return simulatorFrame; }
	public void setFrame( SimulatorFrame simulatorFrame ){ this.simulatorFrame = simulatorFrame; }
	
	public CreateSimulationMenuItem( SimulatorFrame simulatorFrame )
	{
		this.setFrame( simulatorFrame );
		this.setText( "Create" );
		this.setMnemonic( KeyEvent.VK_C );
		this.setIcon( new ImageIcon( this.getClass().getResource( "/icons/create.png" ) ) );
		this.addActionListener( this );
		
		if( this.getFrame().getSimulator().getSdnNetworks().size() == 0 && this.getFrame().getSimulator().getVirtualNetworks().size() == 0 )
			this.setEnabled( false );
		else
			this.setEnabled( true );
	}

	@Override
	public void actionPerformed( ActionEvent actionEvent )
	{
		if( this.checkSimulator() )
		{
			CreateSimulationWizard createSimulationWizard = this.createSimulationWizard();
			
			if( createSimulationWizard.showModalDialog() == 0 )
			{	
				List< SdnNetwork > sdnNetworks = createSimulationWizard.getSdnNetwork();
				List< VirtualNetwork > virtualNetworks = createSimulationWizard.getVirtualNetworks();
				SplittingAlgorithm splittingAlgorithm = createSimulationWizard.getSplittingAlgorithm();
				NodesMappingAlgorithm nodesMappingAlgorithm = createSimulationWizard.getNodesMappingAlgorithm();
				EmbeddingAlgorithm embeddingAlgorithm = createSimulationWizard.getEmbeddingAlgorithm();
				RoundingAlgorithm roundingAlgorithm = createSimulationWizard.getRoundingAlgorithm(); 
				LinksMappingAlgorithm linksMappingAlgorithm = createSimulationWizard.getLinksMappingAlgorithm();
				linksMappingAlgorithm.setBackupVirtualNetwork( createSimulationWizard.isBackup() );
				linksMappingAlgorithm.setCostMetric( createSimulationWizard.getCostMetric() );
				
				Simulation2 simulation = new Simulation2( sdnNetworks, virtualNetworks, splittingAlgorithm, nodesMappingAlgorithm, embeddingAlgorithm, roundingAlgorithm, linksMappingAlgorithm );
				this.getFrame().getSimulator().setSimulation( simulation );
				this.launchSimulation( simulation );
				this.updateTables( createSimulationWizard );
			}
		}
	}
	private boolean checkSimulator()
	{
		boolean checkSimulator = true;

		if( this.getFrame().getSimulator().getSdnNetworks().size() == 0 )
		{
			JOptionPane.showMessageDialog( this.getFrame().getNetworksPanel(), "There are no available substrates to create a simulation", "Substrate needed", 1 );
			checkSimulator = false;
		}
		else if( this.getFrame().getSimulator().getVirtualNetworks().size() == 0 )
		{
			JOptionPane.showMessageDialog( this.getFrame().getNetworksPanel(), "There are no available requests to create a simulation", "Requests needed", 1 );
			checkSimulator = false;
		}
		
		return checkSimulator;
	}
	private CreateSimulationWizard createSimulationWizard()
	{
		CreateSimulationWizard createSimulationWizard = new CreateSimulationWizard();
		createSimulationWizard.getDialog().setTitle( "Create simulation wizard" );
		createSimulationWizard.getDialog().setIconImage( ( new ImageIcon( this.getClass().getResource( "/icons/upcSmall.png" ) ) ).getImage() );
		createSimulationWizard.registerWizardPanel( SdnDescriptor.IDENTIFIER, new SdnDescriptor( this.getFrame().getSimulator().getSdnNetworks() ) );
		createSimulationWizard.registerWizardPanel( VirtualDescriptor.IDENTIFIER, new VirtualDescriptor( this.getFrame().getSimulator().getVirtualNetworks() ) );
		createSimulationWizard.registerWizardPanel( BackupDescriptor.IDENTIFIER, new BackupDescriptor() );
		createSimulationWizard.registerWizardPanel( SplittingDescriptor.IDENTIFIER, new SplittingDescriptor( this.getFrame().getSimulator().getSplittingAlgorithms() ) );
		createSimulationWizard.registerWizardPanel( CoordinatedDescriptor.IDENTIFIER, new CoordinatedDescriptor() );
		createSimulationWizard.registerWizardPanel( EmbeddingDescriptor.IDENTIFIER, new EmbeddingDescriptor( this.getFrame().getSimulator().getEmbeddingAlgorithms() ) );
		createSimulationWizard.registerWizardPanel( RoundingDescriptor.IDENTIFIER, new RoundingDescriptor( this.getFrame().getSimulator().getRoundingAlgorithms() ) );
		createSimulationWizard.registerWizardPanel( NodesDescriptor.IDENTIFIER, new NodesDescriptor( this.getFrame().getSimulator().getNodesMappingAlgorithms() ) );
		createSimulationWizard.registerWizardPanel( LinksDescriptor.IDENTIFIER, new LinksDescriptor( this.getFrame().getSimulator().getLinksMappingAlgorithms() ) );
		createSimulationWizard.registerWizardPanel( CostDescriptor.IDENTIFIER, new CostDescriptor() );
		
		createSimulationWizard.setCurrentPanel( SdnDescriptor.IDENTIFIER );

		Point topLeft = null;
		Dimension parentSize = null;
		
		if( this.getFrame().getNetworksPanel() != null )
		{
			topLeft = this.getFrame().getNetworksPanel().getLocationOnScreen();
			parentSize = this.getFrame().getNetworksPanel().getSize();
			Dimension mySize = createSimulationWizard.getDialog().getPreferredSize();
			createSimulationWizard.getDialog().setLocation( topLeft.x + ( parentSize.width  / 2 ) - ( mySize.width  / 2 ), topLeft.y + ( parentSize.height / 2 ) - ( mySize.height / 2 ) );
		}
		
		return createSimulationWizard;
	}
	private void updateTables( CreateSimulationWizard createSimulationWizard )
	{
		for( SdnNetwork sdnNetwork: createSimulationWizard.getSdnNetwork() )
			sdnNetwork.setState( Network.READY_STATE );
		
		NetworksTableTabbedPane networksTableTabbedPane = this.getFrame().getNetworksPanel().getNetworksTablesTabbedPane();
		
		if( networksTableTabbedPane.getSdnNetworksTable() != null )
			( (SdnTableModel) networksTableTabbedPane.getSdnNetworksTable().getModel() ).refresh();
		
		for( VirtualNetwork virtualNetwork: createSimulationWizard.getVirtualNetworks() )
			virtualNetwork.setState( Network.READY_STATE );
		
		if( networksTableTabbedPane.getVirtualNetworksTable() != null )
			( (VirtualTableModel) networksTableTabbedPane.getVirtualNetworksTable().getModel() ).refresh();
	}
	
	public void launchSimulation( Simulation simulation )
	{
		Point topLeft = this.getFrame().getNetworksPanel().getLocationOnScreen();
		Dimension parentSize = this.getFrame().getNetworksPanel().getSize();
		RunningFrame frameRunning = new RunningFrame( simulation, this.getFrame() );
		frameRunning.setLocation( topLeft.x + ( parentSize.width  / 2 ) - ( frameRunning.getPreferredSize().width  / 2 ), topLeft.y + ( parentSize.height / 2 ) - ( frameRunning.getPreferredSize().height / 2 ) );
		frameRunning.pack();
		frameRunning.setVisible( true );
		frameRunning.getRunningSwingWorker().execute();
	}
	
}
